from django.http import HttpResponse
from django.http import HttpResponseBadRequest
from django.http import HttpResponseForbidden
from django.http import HttpResponseNotAllowed
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
from django.contrib.auth.hashers import check_password
from django.shortcuts import redirect
from django.shortcuts import render_to_response 
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django.core.context_processors import csrf
from django.views.decorators.csrf import ensure_csrf_cookie
from django.core.exceptions import ObjectDoesNotExist
from fonr.alpha.utils import check_phone_number
from fonr.alpha.utils import send_text
from alpha.models import PhoneNumber
from alpha.models import UserProfile
from alpha.models import Activity
from alpha.models import Invite
from alpha.models import MassInvite
from alpha.models import Review
from alpha.models import Feedback
from alpha.models import Prospective
from django.contrib.auth.models import AnonymousUser  # Debug
from fonr.settings import DEBUG
import json

def _log_activity(message, user=None):
  activity = Activity(description=message, user=user)
  activity.save()

def index(request):
  """Index of the site, redirect to home if user is logged in, display sign
  in page otherwise"""
  if request.user.is_authenticated():
    return redirect('home')
  else:
    response = {'request': request}
    response.update(csrf(request))
    return render_to_response('index.html', response)

@login_required    
def verify(request):
  """User gets redirected here if their account is not yet verified"""
  response = {'request': request}
  response.update(csrf(request))
  return redirect('/')  # TODO(Ryan): Add remove this when verification is done
  
def thankyou(request):
  """A thank you page"""
  return render_to_response('thankyou.html', {})

def signup(request):
  """Sign up page.  Create a new account, and redirect to verification."""
  response = {'request': request}
  # CSRF token is used to prevent CSRF attacks, this token will be passed back in
  response.update(csrf(request))
  
  # Just return an empty page if we receive a GET request
  if request.method == 'GET':
    return render_to_response('signup.html', response)
    
  # Try to create a new account
  elif request.method == 'POST':
    if 'prospective' in request.POST:
      # Add them to the prospectives list rather than sign up for a new acct
      try:
        prospective = Prospective(name = request.POST['prospective_name'],
                                  email = request.POST['prospective_email'],
                                  referrer = request.POST['prospective_referrer'])
        prospective.save()
      except Exception, e:
        response['error'] = str(e)
        return render_to_response('signup.html', response)
      else:
        return redirect('/a/thankyou')
    
    response['phone_number'] = request.POST['phone_number'] or ''
    # Check if the invite code exists and is valid
    if 'invite_code' not in request.POST:
      response['error'] = 'Invite code not given'
      return render_to_response('signup.html', response)
    elif Invite.objects.filter(code=request.POST['invite_code']):
      # Keep this in a variable, if user creation is successful then we mark it as used
      invites = Invite.objects.filter(code=request.POST['invite_code'], used=False)
      if not invites:
        response['error'] = 'Invite %s already used' % request.POST['invite_code']
        return render_to_response('signup.html', response)
      else:
        invite = invites[0]
    elif MassInvite.objects.filter(code=request.POST['invite_code']):
      invites = MassInvite.objects.filter(code=request.POST['invite_code'], disabled=False)
      if not invites:
        response['error'] = 'Invite %s is disabled' % request.POST['invite_code']
        return render_to_response('signup.html', response)
      else:
        invite = invites[0]
    else:
      response['error'] = 'Invalid invite code'
      return render_to_response('signup.html', response)
    
    # Clean up the phone number and check if its valid
    raw_number = request.POST['phone_number']
    number_valid, number = check_phone_number(raw_number)
    if not number_valid:
      response['error'] = number
      return render_to_response('signup.html', response)
    
    # Number is valid, now check if the user exists already
    response['phone_number'] = number
    password = request.POST['password']
    user = User.objects.filter(username=number)
    response['user'] = user
    if user:
      # User exists, return an error
      response['error'] = 'User %s already exists' % UserProfile.objects.get(
          user=user).number
      return render_to_response('signup.html', response)
    else:
      # User doesn't exist, make a new user, confirmation code
      confirmation_code = User.objects.make_random_password(length=6, 
          allowed_chars='abcdefghjkmnpqrstuvwxyz23456789')
      user = User.objects.create_user(number, '%s@fonite.com', password)
      user.save()
      phone_number, created = PhoneNumber.objects.get_or_create(number=number)
      profile = UserProfile.objects.get(user=user)
      profile.confirmation_code = confirmation_code
      profile.number = phone_number
      # TODO(Ryan): Remove this after we get verification to work
      profile.valid = True
      profile.save()
      # Just for the invite period, we're not going to bother with number verification
      invite.use(user)
      
      # Used for logging
      _log_activity('Created an account with invite %s' % invite.code, user)
      
      # Sign the user in
      login_user = authenticate(username=number, password=password)
      login(request, login_user)
      return redirect('/a/verify')

  else:
    return HttpResponseBadRequest()
  
def loginpage(request):
  """Authentication end point"""
  response = {'request': request}
  raw_number = request.POST['phone_number']  # Defaults to phone number
  password = request.POST['password']
  number_valid, number = check_phone_number(raw_number)
  user = authenticate(username=number, password=password)
  if user is not None:
    if user.is_active:
      login(request, user)
      _log_activity('Logged in', user)
      return redirect('/')
    else:
      return render_to_response('disabled.html', {})
  else:
    response.update({'phone_number': number})
    response.update(csrf(request))
    return render_to_response('login_failed.html', response)

@login_required
def home(request):
  """Home of the site, havn't really decided what goes here, maybe recent
  activity?"""
  response = {'is_home': True, 'request': request}
  return render_to_response('home.html', response)

@login_required
def search(request, query=None):
  """Returns info on a phone number if found, 'NOT FOUND' page otherwise"""
  response = {'query': query, 'request': request}
  response.update(csrf(request))
  
  # Redirect request if its not in canotical form
  if not query:
    response['is_search'] = True
    if 'phone_number' in request.POST:
      raw_number = request.POST['phone_number']
      number_valid, number = check_phone_number(raw_number)
      if number_valid:
        return redirect('/a/search/%s' % number)
      else:
        response['error'] = number
        return render_to_response('search.html', response)
    else:
      return render_to_response('search.html', response)
      
  # Check validity (Should be valid, but wouldn't hurt)
  number_valid, number = check_phone_number(query)
  if not number_valid:
    response['error'] = number
    return render_to_response('search.html', response)
    
  # Retrieve and return review
  phone_number, created = PhoneNumber.objects.get_or_create(number=number)
  if 'new_review' in request.POST:
    # Post a new review if requested
    review = Review(
        number=phone_number, 
        text=request.POST['new_review'],
        user=request.user
    )
    review.save()
    _log_activity('Posted a review for %s' % phone_number, 
                  request.user)
  else:
    _log_activity('Accessed %s' % phone_number, request.user)
  reviews = Review.objects.filter(number=phone_number, 
      valid=True).order_by('-date')
  response['reviews'] = reviews
  response['phone_number'] = phone_number
  response['is_self'] = (request.user.username == phone_number.number)
  if response['is_self']:
    response['is_profile'] = True
  else:
    response['is_search'] = True
  response['user'] = request.user
  return render_to_response('review.html', response)
  
def vote(request, review_id):
  """Vote up, vote down, or clear vote."""
  response = {}
  if request.method != 'POST':
    return HttpResponseNotAllowed(['POST'])
  command = request.POST['command']
  review = Review.objects.get(pk=review_id)
  user = request.user
  if command == 'up':
    if user in review.vote_ups.all():
      response['success'] = 'false'
      response['message'] = 'Already voted'
    elif user in review.vote_downs.all():
      response['success'] = 'true'
      review.vote_downs.remove(user)
      review.vote_ups.add(user)
      review.votes += 2
      review.save()
    else:
      response['success'] = 'true'
      review.vote_ups.add(user)
      review.votes += 1
      review.save()
  elif command == 'down':
    if user in review.vote_downs.all():
      response['success'] = 'false'
      response['message'] = 'Already voted'
    elif user in review.vote_ups.all():
      response['success'] = 'true'
      review.vote_ups.remove(user)
      review.vote_downs.add(user)
      review.votes -= 2
      review.save()
    else:
      response['success'] = 'true'
      review.vote_downs.add(user)
      review.votes -= 1
      review.save()
  elif command == 'clear':
    if user in review.vote_downs.all():
      response['success'] = 'true'
      review.vote_downs.remove(user)
      review.votes += 1
      review.save()
    elif user in review.vote_ups.all():
      response['success'] = 'true'
      review.vote_ups.remove(user)
      review.votes -= 1
      review.save()
    else:
      response['success'] = 'true'
      response['message'] = 'Nothing happened'
  else:
    response['message'] = 'No command given'
  response['votes'] = review.votes
  if response['success'] == 'true':
    reviewee = (review.number
        if review.number != request.user.get_profile().number
        else 'self')
    reviewer = review.user if review.user != request.user else 'self'
    _log_activity('Voted %s review of %s by %s' % (command,
        reviewee, reviewer), request.user)
  return HttpResponse(json.dumps(response))
  
@login_required
@ensure_csrf_cookie
def single_review(request, review_id):
  """Returns full text of a single review, allow voting"""
  response = {'request': request}
  review = Review.objects.get(pk=review_id)
  if request.method == 'POST':
    if request.POST['command'] == 'delete':
      if request.user == review.user:
        review.valid = False
        review.save()
        _log_activity('Deleted review of %s' % review.number, request.user)
        return redirect('/a/search/' + review.number.number)
  response['review'] = review
  response['phone_number'] = review.number
  response['is_self'] = (request.user.username == review.number.number)
  response['is_reviewer'] = (request.user == review.user)
  if response['is_self']:
    _log_activity('Views review of self', request.user)
    response['is_profile'] = True
  else:
    _log_activity('Views review of %s' % review.number, request.user)
    response['is_search'] = True
  response['user'] = request.user
  response.update(csrf(request))
  return render_to_response('single_review.html', response)
  
def logout_page(request):
  _log_activity('Logs out', request.user)
  logout(request)
  return redirect("/")

def profile(request):
  """View and edit own page"""
  _log_activity('Views own profile', request.user)
  return search(request, request.user.username)
  
def report(request):
  response = {'request': request}
  response.update(csrf(request))
  if request.method == 'GET':
    response['redirect_url'] = request.GET['from']
    return render_to_response('report.html', response)
  elif request.method == 'POST':  
    feedback = Feedback(type=request.POST['type'], user=request.user, 
                        text=request.POST['text'], url=request.POST['from'])
    feedback.save()
    _log_activity('Writes report', request.user)
    return redirect(request.POST['from'])
  
@login_required
def settings(request):
  """Change user settings"""
  response = {'is_settings': True, 'request': request}
  response.update(csrf(request))
  if request.method == 'POST':
    command = request.POST['command']
    if command == 'change_password':
      if check_password(request.POST['old_password'], request.user.password):
        if request.POST['new_password'] == request.POST['confirm_password']:
          user = request.user
          user.set_password(request.POST['new_password'])
          user.save()
          _log_activity('Changes password', request.user)
          response['info_message'] = 'Password changed successfully'
        else:
          response['error_message'] = 'Passwords did not match'
      else:
        response['error_message'] = 'Old password incorrect'
    else:
      response['error_message'] = 'Invalid command %s' % command
  
  return render_to_response('settings.html', response)
